package com.baitiaojun.user.service.impl;

import com.baitiaojun.api.domain.user.User;
import com.baitiaojun.api.domain.user.UserCoin;
import com.baitiaojun.api.domain.user.UserInfo;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.*;
import com.baitiaojun.api.vo.JsonRes;
import com.baitiaojun.user.config.AsyncConfig;
import com.baitiaojun.user.feign.ElasticsearchFeign;
import com.baitiaojun.user.feign.UserAuthoritiesFeign;
import com.baitiaojun.user.mapper.UserCoinMapper;
import com.baitiaojun.user.mapper.UserInfoMapper;
import com.baitiaojun.user.mapper.UserMapper;
import com.baitiaojun.user.service.SystemService;
import com.baitiaojun.user.support.RedisSupport;
import com.baitiaojun.user.support.UserSupport;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @类名 SystemServiceImpl
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2023/2/23 16:02
 * @版本 1.0
 */
@Service
public class SystemServiceImpl implements SystemService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private RedisSupport redisSupport;

    @Resource
    private UserSupport userSupport;

    @Resource
    private UserCoinMapper userCoinMapper;

    @Autowired
    private UserAuthoritiesFeign userAuthoritiesFeign;

    @Autowired
    private AsyncConfig asyncConfig;

    @Autowired
    private ElasticsearchFeign elasticsearchFeign;

    @Override
    @GlobalTransactional(name = "创建用户和角色事务")
    public void register(User user) throws Exception {
        if (ObjectUtils.isEmpty(user.getPhone())) {
            throw new ConditionException("手机号不能为空");
        }
        if (ObjectUtils.isNotEmpty(getUserByPhone(user.getPhone()))) {
            throw new ConditionException("该手机号已经注册");
        }
        String password = user.getPassword();
        if (StringUtils.isEmpty(password)) {
            throw new ConditionException("密码不能为空");
        }
        try {
            password = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("解密失败");
        }
        String salt = String.valueOf(SnowFlakeUtil.getNextId());
        Date date = new Date();
        user = User.builder().id(SnowFlakeUtil.getNextId())
                .password(MD5Util.sign(password, salt, ConstantUtil.CHAR_SET_UTF8))
                .phone(user.getPhone())
                .email(user.getEmail())
                .salt(salt)
                .createtime(date)
                .build();
        int resUser = userMapper.insertSelective(user);
        if (resUser == 0) {
            throw new ConditionException("用户系统信息更新失败");
        }
        Long userId = user.getId();
        UserInfo userInfo = UserInfo.builder().id(SnowFlakeUtil.getNextId())
                .userid(userId)
                .nick(ConstantUtil.DEFAULT_NICKNAME_PREFIX
                        + String.valueOf(SnowFlakeUtil.getNextId()).substring(0, 12))
                .avatar(ConstantUtil.DEFAULT_AVATAR)
                .sign(ConstantUtil.DEFAULT_SIGN)
                .gender(String.valueOf(ConstantUtil.Gender.MALE.getGender()))
                .createtime(date)
                .coinCount(0)
                .fansCount(0)
                .followed(false)
                .build();
        int resUserInfo = userInfoMapper.insertSelective(userInfo);
        if (resUserInfo == 0) {
            throw new ConditionException("用户个人信息添加失败");
        }
        //添加用户拥有的硬币记录
        UserCoin userCoin = new UserCoin();
        userCoin.setId(SnowFlakeUtil.getNextId());
        userCoin.setUserid(userId);
        userCoin.setAmount(0L);
        userCoin.setCreatetime(new Date());
        int res = userCoinMapper.insertSelective(userCoin);
        if (res == 0) {
            throw new ConditionException("添加用户硬币记录失败");
        }
        //加密avatar字段
        AESUtil aesUtil = AESUtil.lazyGetAesUtil();
        userInfo.setAvatar(aesUtil.encrypt(userInfo.getAvatar()));
        //添加默认角色
        JsonRes jsonRes = userAuthoritiesFeign.addDefaultRole(userId);
        if (jsonRes.get("status").equals(500)) {
            throw new ConditionException("添加用户角色失败");
        }
        //保存到userinfo信息es
        ThreadPoolExecutor asyncExecutor = asyncConfig.getAsyncExecutor();
        asyncExecutor.execute(() -> elasticsearchFeign.saveUserInfo(userInfo));
    }

    @Override
    public User getUserByPhone(String phone) {
        return userMapper.selectUserByPhone(phone);
    }

    /**
     * 1、网关转发到登录服务
     * 2、用户手机号是否为空
     * 3、用户是否存在
     * 4、密码验证
     * 5、所有验证通过后用JWT来获取token
     * 6、获取到token以后将toke保存到redis缓存，token作为key，user信息作为value
     * @param user
     * @return
     * @throws ConditionException
     */
    @Override
    public String login(User user) throws Exception {
        String phone = user.getPhone();
        if (StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号码为空");
        }
        User userByPhone = getUserByPhone(phone);
        if (ObjectUtils.isEmpty(userByPhone)) {
            throw new ConditionException("不存在此用户");
        }
        Object value = redisSupport.getValue(ConstantUtil.ONLINE + phone);
        if (ObjectUtils.isNotEmpty(value)) {
            throw new ConditionException("此用户已经登录");
        }
        String password;
        try {
            password = RSAUtil.decrypt(user.getPassword());
        } catch (Exception e) {
            throw new ConditionException("解密失败");
        }
        String sign = MD5Util.sign(password, userByPhone.getSalt(), ConstantUtil.CHAR_SET_UTF8);
        user = userMapper.selectUserBySign(sign);
        if (ObjectUtils.isEmpty(user)) {
            throw new ConditionException("用户密码错误");
        }
        Long id = user.getId();
        //获取刷新token
        String refreshToken = TokenUtil.generateToken(id, ConstantUtil.TokenType.REFRESH);
        //通过token
        String accessToken = TokenUtil.generateToken(id, ConstantUtil.TokenType.ACCESS);
        userSupport.addUserToRedis(accessToken, refreshToken, getUserAndUserInfo(id));
        //缓存登录记录到redis
        redisSupport.setValue(ConstantUtil.ONLINE + phone, "online", ConstantUtil.REDIS_ONLINE_TIMEOUT, TimeUnit.DAYS);
        return accessToken;
    }

    @Override
    public User getUserAndUserInfo(Long userId) throws Exception {
        User user = userMapper.selectByPrimaryKey(userId);
        UserInfo userInfo = userInfoMapper.selectByUserId(userId);
        AESUtil aesUtil = AESUtil.lazyGetAesUtil();
        userInfo.setAvatar(aesUtil.encrypt(userInfo.getAvatar()));
        user.setUserInfo(userInfo);
        return user;
    }

    @Override
    public void cancellation(String token, String phone) {
        redisSupport.delete(token);
        redisSupport.delete(ConstantUtil.ONLINE+phone);
    }
}
